#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <linux/videodev2.h>
#include <sys/ioctl.h>
#include <getopt.h>

// 定义UVC 1.1支持的常见控制ID
#define CTRL_BRIGHTNESS      V4L2_CID_BRIGHTNESS
#define CTRL_CONTRAST        V4L2_CID_CONTRAST
#define CTRL_SATURATION      V4L2_CID_SATURATION
#define CTRL_HUE             V4L2_CID_HUE
#define CTRL_GAMMA           V4L2_CID_GAMMA
#define CTRL_WHITE_BALANCE   V4L2_CID_WHITE_BALANCE_TEMPERATURE
#define CTRL_EXPOSURE        V4L2_CID_EXPOSURE
#define CTRL_GAIN            V4L2_CID_GAIN
#define CTRL_SHARPNESS       V4L2_CID_SHARPNESS
#define CTRL_AUTO_WB         V4L2_CID_AUTO_WHITE_BALANCE
#define CTRL_AUTO_EXPOSURE   V4L2_CID_AUTO_EXPOSURE_BIAS
#define CTRL_FOCUS_ABSOLUTE  V4L2_CID_FOCUS_ABSOLUTE
#define CTRL_FOCUS_AUTO      V4L2_CID_FOCUS_AUTO
#define CTRL_ZOOM_ABSOLUTE   V4L2_CID_ZOOM_ABSOLUTE

// 设置控制参数
int set_control(int fd, int control_id, int value) {
    struct v4l2_control control;
    control.id = control_id;
    control.value = value;

    if (ioctl(fd, VIDIOC_S_CTRL, &control) == -1) {
        perror("Setting control failed");
        return -1;
    }
    return 0;
}


// 获取控制参数当前值
int get_control(int fd, int control_id, int *value) {
    struct v4l2_control control;
    control.id = control_id;

    if (ioctl(fd, VIDIOC_G_CTRL, &control) == -1) {
        perror("Getting control failed");
        return -1;
    }
    *value = control.value;
    return 0;
}

// 列出设备支持的所有控制参数
void list_controls(int fd) {
    struct v4l2_queryctrl qctrl;
    memset(&qctrl, 0, sizeof(qctrl));
    qctrl.id = V4L2_CTRL_CLASS_USER | V4L2_CTRL_FLAG_NEXT_CTRL;

    printf("\n=== Supported Controls ===\n");
    while (ioctl(fd, VIDIOC_QUERYCTRL, &qctrl) == 0) {
        if (qctrl.flags & V4L2_CTRL_FLAG_DISABLED)
            continue;

        printf("ID: 0x%08x, Name: %s\n", qctrl.id, qctrl.name);
        printf("  Type: %d, Min: %d, Max: %d, Step: %d, Default: %d\n\n",
               qctrl.type, qctrl.minimum, qctrl.maximum, qctrl.step, qctrl.default_value);

        qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
    }
}

// 设置所有参数为默认值
int set_defaults(int fd) {
    if (set_control(fd, CTRL_BRIGHTNESS, 128) == -1) return -1;
    if (set_control(fd, CTRL_CONTRAST, 128) == -1) return -1;
    if (set_control(fd, CTRL_SATURATION, 128) == -1) return -1;
    if (set_control(fd, CTRL_HUE, 0) == -1) return -1;
    if (set_control(fd, CTRL_GAMMA, 100) == -1) return -1;
    if (set_control(fd, CTRL_WHITE_BALANCE, 4000) == -1) return -1;
    if (set_control(fd, CTRL_EXPOSURE, 50) == -1) return -1;
    if (set_control(fd, CTRL_GAIN, 0) == -1) return -1;
    if (set_control(fd, CTRL_SHARPNESS, 128) == -1) return -1;
    if (set_control(fd, CTRL_AUTO_WB, 1) == -1) return -1;  // 自动白平衡
    if (set_control(fd, CTRL_AUTO_EXPOSURE, 1) == -1) return -1;  // 自动曝光 (1表示启用)
    if (set_control(fd, CTRL_FOCUS_AUTO, 1) == -1) return -1;  // 自动对焦
    return 0;
}

// 打印使用帮助
void print_help(char *prog_name) {
    printf("Usage: %s [options]\n\n", prog_name);
    printf("Options:\n");
    printf("  -d, --device <path>   Specify video device path (default: /dev/video0)\n");
    printf("  -l, --list            List all supported controls\n");
    printf("  -b, --brightness <val> Set brightness (0-255)\n");
    printf("  -c, --contrast <val>   Set contrast (0-255)\n");
    printf("  -s, --saturation <val> Set saturation (0-255)\n");
    printf("  -h, --hue <val>        Set hue (-180-180)\n");
    printf("  -g, --gamma <val>      Set gamma (1-500)\n");
    printf("  -w, --whitebalance <val> Set white balance temperature (2800-6500)\n");
    printf("  -e, --exposure <val>   Set exposure (1-1000)\n");
    printf("  -a, --gain <val>       Set gain (0-100)\n");
    printf("  -r, --sharpness <val>  Set sharpness (0-255)\n");
    printf("  -f, --focus <val>      Set focus absolute value (0-1000)\n");
    printf("  -z, --zoom <val>       Set zoom absolute value (100-500)\n");
    printf("  -A, --auto-wb <0|1>    Enable/disable auto white balance\n");
    printf("  -E, --auto-exposure <0|1> Enable/disable auto exposure\n");
    printf("  -F, --auto-focus <0|1> Enable/disable auto focus\n");
    printf("  -D, --defaults         Set all controls to default values\n");
    printf("  -H, --help             Display this help message\n\n");
    printf("Example: %s --device /dev/video1 --brightness 150 --contrast 180\n", prog_name);
}

int main(int argc, char *argv[]) {
    const char *device = "/dev/video0";
    int fd, c;
    int set_brightness = -1, set_contrast = -1, set_saturation = -1;
    int set_hue = -1, set_gamma = -1, set_whitebalance = -1;
    int set_exposure = -1, set_gain = -1, set_sharpness = -1;
    int set_focus = -1, set_zoom = -1;
    int set_auto_wb = -1, set_auto_exposure = -1, set_auto_focus = -1;
    int list = 0, defaults = 0;

    // 解析命令行参数
    while (1) {
        static struct option long_options[] = {
            {"device",      required_argument, 0, 'd'},
            {"list",        no_argument,       0, 'l'},
            {"brightness",  required_argument, 0, 'b'},
            {"contrast",    required_argument, 0, 'c'},
            {"saturation",  required_argument, 0, 's'},
            {"hue",         required_argument, 0, 'h'},
            {"gamma",       required_argument, 0, 'g'},
            {"whitebalance",required_argument, 0, 'w'},
            {"exposure",    required_argument, 0, 'e'},
            {"gain",        required_argument, 0, 'a'},
            {"sharpness",   required_argument, 0, 'r'},
            {"focus",       required_argument, 0, 'f'},
            {"zoom",        required_argument, 0, 'z'},
            {"auto-wb",     required_argument, 0, 'A'},
            {"auto-exposure",required_argument,0, 'E'},
            {"auto-focus",  required_argument, 0, 'F'},
            {"defaults",    no_argument,       0, 'D'},
            {"help",        no_argument,       0, 'H'},
            {0, 0, 0, 0}
        };

        int option_index = 0;
        c = getopt_long(argc, argv, "d:lb:c:s:h:g:w:e:a:r:f:z:A:E:F:DH", long_options, &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 'd':
            device = optarg;
            break;
        case 'l':
            list = 1;
            break;
        case 'b':
            set_brightness = atoi(optarg);
            break;
        case 'c':
            set_contrast = atoi(optarg);
            break;
        case 's':
            set_saturation = atoi(optarg);
            break;
        case 'h':
            set_hue = atoi(optarg);
            break;
        case 'g':
            set_gamma = atoi(optarg);
            break;
        case 'w':
            set_whitebalance = atoi(optarg);
            break;
        case 'e':
            set_exposure = atoi(optarg);
            break;
        case 'a':
            set_gain = atoi(optarg);
            break;
        case 'r':
            set_sharpness = atoi(optarg);
            break;
        case 'f':
            set_focus = atoi(optarg);
            break;
        case 'z':
            set_zoom = atoi(optarg);
            break;
        case 'A':
            set_auto_wb = atoi(optarg);
            break;
        case 'E':
            set_auto_exposure = atoi(optarg);
            break;
        case 'F':
            set_auto_focus = atoi(optarg);
            break;
        case 'D':
            defaults = 1;
            break;
        case 'H':
            print_help(argv[0]);
            return EXIT_SUCCESS;
        default:
            print_help(argv[0]);
            return EXIT_FAILURE;
        }
    }

    // 打开设备
    fd = open(device, O_RDWR);
    if (fd == -1) {
        perror("Opening video device");
        return EXIT_FAILURE;
    }

    // 列出支持的控制参数
    if (list) {
        list_controls(fd);
        close(fd);
        return EXIT_SUCCESS;
    }

    // 设置默认值
    if (defaults) {
        if (set_defaults(fd) == -1) {
            close(fd);
            return EXIT_FAILURE;
        }
        printf("All controls set to default values.\n");
    }

    // 设置各参数
    if (set_brightness != -1) {
        if (set_control(fd, CTRL_BRIGHTNESS, set_brightness) == -1) {
            close(fd);
            return EXIT_FAILURE;
        }
        printf("Brightness set to %d\n", set_brightness);
    }

    if (set_contrast != -1) {
        if (set_control(fd, CTRL_CONTRAST, set_contrast) == -1) {
            close(fd);
            return EXIT_FAILURE;
        }
        printf("Contrast set to %d\n", set_contrast);
    }

    if (set_saturation != -1) {
        if (set_control(fd, CTRL_SATURATION, set_saturation) == -1) {
            close(fd);
            return EXIT_FAILURE;
        }
        printf("Saturation set to %d\n", set_saturation);
    }

    if (set_hue != -1) {
        if (set_control(fd, CTRL_HUE, set_hue) == -1) {
            close(fd);
            return EXIT_FAILURE;
        }
        printf("Hue set to %d\n", set_hue);
    }

    if (set_gamma != -1) {
        if (set_control(fd, CTRL_GAMMA, set_gamma) == -1) {
            close(fd);
            return EXIT_FAILURE;
        }
        printf("Gamma set to %d\n", set_gamma);
    }

    if (set_whitebalance != -1) {
        if (set_control(fd, CTRL_WHITE_BALANCE, set_whitebalance) == -1) {
            close(fd);
            return EXIT_FAILURE;
        }
        printf("White balance set to %d\n", set_whitebalance);
    }

    if (set_exposure != -1) {
        if (set_control(fd, CTRL_EXPOSURE, set_exposure) == -1) {
            close(fd);
            return EXIT_FAILURE;
        }
        printf("Exposure set to %d\n", set_exposure);
    }

    if (set_gain != -1) {
        if (set_control(fd, CTRL_GAIN, set_gain) == -1) {
            close(fd);
            return EXIT_FAILURE;
        }
        printf("Gain set to %d\n", set_gain);
    }

    if (set_sharpness != -1) {
        if (set_control(fd, CTRL_SHARPNESS, set_sharpness) == -1) {
            close(fd);
            return EXIT_FAILURE;
        }
        printf("Sharpness set to %d\n", set_sharpness);
    }

    if (set_focus != -1) {
        if (set_control(fd, CTRL_FOCUS_ABSOLUTE, set_focus) == -1) {
            close(fd);
            return EXIT_FAILURE;
        }
        printf("Focus set to %d\n", set_focus);
    }

    if (set_zoom != -1) {
        if (set_control(fd, CTRL_ZOOM_ABSOLUTE, set_zoom) == -1) {
            close(fd);
            return EXIT_FAILURE;
        }
        printf("Zoom set to %d\n", set_zoom);
    }

    if (set_auto_wb != -1) {
        if (set_control(fd, CTRL_AUTO_WB, set_auto_wb) == -1) {
            close(fd);
            return EXIT_FAILURE;
        }
        printf("Auto white balance %s\n", set_auto_wb ? "enabled" : "disabled");
    }

    if (set_auto_exposure != -1) {
        if (set_control(fd, CTRL_AUTO_EXPOSURE, set_auto_exposure) == -1) {
            close(fd);
            return EXIT_FAILURE;
        }
        printf("Auto exposure %s\n", set_auto_exposure ? "enabled" : "disabled");
    }

    if (set_auto_focus != -1) {
        if (set_control(fd, CTRL_FOCUS_AUTO, set_auto_focus) == -1) {
            close(fd);
            return EXIT_FAILURE;
        }
        printf("Auto focus %s\n", set_auto_focus ? "enabled" : "disabled");
    }

    printf("Controls set successfully.\n");
    close(fd);
    return EXIT_SUCCESS;
}